/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

namespace cvm
{
	struct Undefined : ValType<BaseType> {
		virtual PChar TypeName() { return "Undefined"; }
	};
	Undefined gUndefined;

	// The "Any" type is a 
	struct Any
	{
		// fields
		union holder
		{
			void* vp;
			double d;
			int n;
			bool b;
			char c;
			PChar pc;
		}
		data;

		BaseType* type;

		// ctor
		Any() 
			: type(&gUndefined)
		{
		}

		Any(Any& a) 
			: type(a.type), data(a.data)
		{
			a.SetUndefined();
		}

		template<typename T>
		T* As() {
			return dynamic_cast<T*>(type);
		}

		void SetUndefined() 
		{
			type = &gUndefined;
			data.n = 0;
		}

		Any(bool x);
		Any(int x);
		Any(double x);
		Any(char x);
		Any(PChar x);
		Any(FILE* x);

		void IncRef() {
			type->IncRef(*this);
		}

		void DecRef() {
			type->DecRef(*this);
		}

		int RefCnt() {
			return type->RefCnt(*this);
		}

		void operator=( Any& x) {
			DecRef();
			data = x.data;
			type = x.type;
			x.SetUndefined();
		}

		template<typename T>
		void operator=(T x) {
			Any tmp(x);
			this->operator=(tmp);
		}

		void CopyFrom(Any& x) {
			DecRef();
			data = x.data;
			type = x.type;
			IncRef();
			Assert(RefCnt() == x.RefCnt());
		}

		void CopyTo(Any& a) {
			a.CopyFrom(*this);
		}

		int& ToInt() { return data.n; }
		bool& ToBool() { return data.b; }
		char& ToChar() { return data.c; }
		PChar& ToPChar() { return data.pc; }
		double& ToDbl() { return data.d; }

		// TODO: deprecate
		FILE*& ToFile() { return ToPtr<FILE>(); }
		
		template<typename T>
		T*& ToPtr() { return reinterpret_cast<T*>(data.vp); }

		void Write(FILE* f = stdout) {
			Any a(f);
			type->Write(*this, a);
			a.DecRef();
		}

		template<typename T>
		T* GetInterface() {
			T* r = dynamic_cast<T*>(type);
			assert(r != NULL);
			return r;
		}
	};

	// Global functions
	void Move(Any& from, Any& to) {
		from = to;
	}
	void Copy(Any& from, Any& to) {
		from.CopyFrom(to);
	}

	// Helper class, wraps an Any in a scope
	// for automatic reference count decrementing
	struct ScopedAny {
		Any any;
		~ScopedAny() {
			any.DecRef();
		}
	};
}

